home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Mag HDD Backup
/
Amiga Mag HDD Backup.zip
/
Amiga Mag HDD Backup
/
Alexander.img.bin
/
Alexander.img
/
***9.11 All NEWer important
/
Stockman⁄StructDraw Post
/
HPGL2.asc
< prev
next >
Wrap
Text File
|
1994-09-16
|
25KB
|
407 lines
Douglas Stockman
Creating Structured Drawings - Part 2: HP-GL/2
In the first structured drawing format article I introduced the concept of a structured drawing and
discussed the PostScript language. This article focuses on the Hewlett Packard Graphics Language
(HP-GL/2) standard. HP-GL/2 is most commonly used when sending output to graphics plotters,
although some programs use it to store and transfer structured graphics. A number of different versions
of HP-GL exist. HP-GL/2 is the most current standard and will be the focus of this article. Older
plotters such as HP's 7475A do not support HP-GL/2, but rather a more limited and earlier version of
HP-GL. The concepts on how to use each version of HP-GL are the same, but some of the commands
differ. A list of references are provided at the end of this article for both an early version of HP-GL and
the current standard HP-GL/2.
For the beginning programmer, an attractive feature of the language is that HP-GL/2 commands are
saved as ASCII text. Therefore, an HP-GL/2 defined structured drawing can be created using a text
editor. It is also easier to debug code that outputs HP-GL/2 commands because errors in the program's
output can be viewed with a text editor. One drawback to learning HP-GL/2 on the Amiga is that no
software interpreter exists for HP-GL/2 commands such as Post for PostScript. A software interpreter
named PLT does exist for an earlier version of the HP-GL standard, but as of 12/93 this interpreter did
not support HP-GL/2. Therefore, to truly debug HP-GL/2 generating code, the programmer must find an
HP-GL/2 capable device such as a plotter. For those who are developing commercial applications, HP
does have a peripherals developer support program which allows programmers to borrow plotters.
HP-GL/2 commands are two letter mnemonics. For example, the command to lift the plotter's pen off
the paper is PU. To place the pen down is PD. To draw an arc using absolute coordinates, the AA
command is used. HP-GL/2 commands always use uppercase. Many of these two letter commands are
followed by one or more numerical parameters. The PU command not only lifts the pen off the paper,
but can also move the pen to a specified location. To move the pen to the coordinates X=1016, Y=2032,
the programmer writes PU1016,2032. The PU command is very similar to the Amiga graphics function
Move(). If the programmer wants to put the pen down and then move to X=2032, Y=5280, the PD
command appears as follows: PD2032,5280. The PD command is similar to the Amiga's Draw()
function. In an ASCII file the two HP-GL/2 commands generally appear one right after the other:
PU1016,2032PD2032,5280. Each command can be terminated by a semicolon ";", but this is not
recommended for most commands because it is not required and it increases the number of bytes that
must be sent from the computer to the plotter. This means slower plotting times for complex drawings.
The coordinates X=1016 and Y=2032 were used for a reason in the last paragraph. The default plotter
scale is one inch equals 1016 plotter units. Therefore, the PU1016,2032 command moves the pen to
X=1 inch and Y=2 inch. If using the metric scale, one cm therefore equals 400 plotter units. It is
important to note that HP-GL/2's default page orientation is Landscape. Therefore, the X axis is oriented
along the long axis of the paper (the 11 inch side on an 8.5x11 inch paper). This is different from
PostScript's default page orientation which is Portrait. As for PostScript, the default origin in the
HP-GL/2 coordinate system is the lower left corner of the paper. HP-GL/2 allows the user to define
their own scale when drawing, but the resolution of the device cannot be any finer than 1/1016th of an
inch (0.00098 inch). This should prove more than adequate for most applications.
HP-GL/2's default plotter units may be a bit cumbersome to work with. Therefore, the user can define
their own scaling system. By using the SC command, the user can define plotter coordinates in inches.
Once the SC command is used to scale plotter units to inches, all page coordinates are interpreted as
inches. The above PU1016,2032 command would be written as PU1.0,2.0. Another common way to
scale the coordinate system is to set the page up to equal the screen coordinates. For example, if the
screen size is 640x400 pixels, the plotter page can be scaled to 640 units along the 11 inch X axis and
400 units along the 8.5 inch Y axis. Therefore, when sending a screen oriented drawing to the plotter, no
further manipulations are needed. Because the plotter has a much higher resolution than the screen, all
coordinate calculations should be done with at least 5 digits resolution and the numbers rounded off
when they are used for drawing to the screen. For example, coordinate 325.257, 185.961 is sent to the
plotter unchanged, while the numbers 325, 186 are used to draw to the screen.
To change the scale of the plot the user issues the SC command which has a parameter list as follows:
SC Xmin, Xmax, Ymin, Ymax. To set the plotter scale to equal that of a 640x400 pixel Amiga screen,
the user writes the SC command as follows:
SC0.0,640.0,400.0,0.0
Note that Ymin was entered as 400.0. This is because the left lower corner of the plotter coordinate
system is Xmin=0, Ymin=0, while the left lower corner of am Amiga screen is Xmin=0, Ymax=400.
After the SC command is executed the plotter scale mimics the screen's scale with lower Y values being
closer to the top of the page. Instead of altering the plotters coordinates, the programmer may decide to
alter the screen coordinates as was done with the MAP_Y() definition in the first article.
Another important aspect of the plotter's coordinate system that must be learned is the use of the scaling
points P1 and P2. One is tempted to assume that the SC, scale, command is used to enlarge or reduce a
plot's size. This is not the case. SC sets the units of measure that the plotter uses to specify location.
The scaling points P1 and P2 control any enlarging or reducing of a plot. Usually, the plotter will be
initialized with the IN command before any plot-specific commands are sent. IN sets P1 and P2 to the
default values. P1 is at the lower left corner and P2 is at the upper right corner. An SC command must
then be issued to set up a scale that the P1 and P2 points will use. To reduce the subsequent plot, points
P1 and P2 are moved closer together. To enlarge the plot, P1 and P2 are moved further apart. The IP, or
input P1 and P2, command is used to change the locations of P1 and P2. The parameter list for IP is:
IP P1x, P1y, P2x, P2y
Of note, instead of using the IN command to set P1 and P2 to the default parameters, the user can set the
initial P1 and P2 locations using the IP command.
To reduce a plot in half, the following pseudocode can be used.
IP0,0,2000,2000
SC0,640.0,400.0,0.0
IP500,500,1500,1500
/* now draw the plot */
P1 is first set to location 0,0 (i.e. lower left corner) and P2 to 2000,2000. Next, the plot is scaled using
the SC command. Reducing and enlarging can only occur when the scaling points (P1, P2) are used in
concert with the scaling command (SC). The next occurrence of the IP command moves P1 and P2
closer by 1000 plotter units. This effectively reduces the final plot size in half. The plot was to be 2000
unit by 2000 units. It is now 1000 units by 1000. This is a very simplified view of the use of the IP and
SC commands, but it provides a flavor for the potential. Of note, remember that HP-GL/2 commands
are not entered with only one command per line as in the previous examples. The actual appearance of
the commands in a file would be:
IP0,0,2000,2000,SC0,400,640,0,IP500,500,1500,1500;
It is time to create our first drawing. To keep it simple, we will just create a small rectangle. The
HP-GL/2 code is generated using a simple C language file. Almost any language will do. The HP-GL/2
code can even be entered directly into a text editor.
#include <stdio.h>
void main(main){
printf("%c%%-1BBPINSP1SC0.0,640.0,400.0,0.0", 27);
printf("PU100,100PD200,100PD200,200PD100,200PD100,100");
printf("PUSP0PG;");
exit(0);
}
Save the program as HPrec.c, compile and link. From the CLI, send the output of the command to
whichever device, either the serial or parallel port, the plotter is attached to.
HPrec > par:
A rectangle should be drawn by the plotter.
The first printf() statement contains many new commands that must be mentioned. Fortunately, most of
this first line can remain unchanged for the majority of plots. The first part of the string %c%%-1B"
(human readable==ESC%-1B) ensures that the device is in HP-GL/2 mode. Many newer laser printers
support HP-GL/2 in addition to the more traditional PCL and PostScript capabilities. This command
tells the device to select HP-GL/2 emulation mode. The BP command stands for Begin Plot. This
informs the plotter device to prepare a new piece of paper. It also informs any plotter that supports both
HP-GL and HP-GL/2 to select HP-GL/2 emulation mode. The IN, Initialize Plotter, command does just
that. It initializes the plotter back to its default settings. The SP1 command Selects Pen number 1. On a
multi-pen machine, this foreground color is usually black. The SC command has already been
discussed. Any graphics commands that follow will now use coordinates similar to screen coordinates.
The next printf() command creates the rectangle. PU100,100 lifts the pen off the paper and moves to
position 100,100. The following PD commands put the pen down on the paper and draw the four sides
of the rectangle. Of note, the preferred method of writing the PD command is somewhat different than
shown. To decrease the number of bytes that must be sent to the plotter, the PD command can be used
once and all the following PD-related coordinates follow. For example, the command can be written as:
printf("PU100,100PD200,100,200,200,100,200,100,100");
A number of HP-GL/2 commands work this way. You do not have to re-write the PD command until
you use another command. Therefore, you can draw a multi-sided polygon using one PD command
followed only by the actual numerical coordinates.
The final printf() command terminates the plot. PU lifts the pen off the paper. SP0 selects pen 0. This
command basically puts pen 1 away so the ink will not dry out. The PG command tells the plotter that
the plot is done and to advance the page if the device supports this feature. If the device cannot advance
the page, the plotter is set to a Not Ready state so that the user has to manually advance the page. Please
note that PG must be followed by a semicolon. The one exception to this rule is that the PG command
can be followed by the RP command which must be terminated with a semicolon. RP stands for RePlot
and can be used to instruct the plotter to make multiple copies of the current drawing. The number of
copies RP creates is controlled by an integer value that follows the RP command. To create 10 copies of
the current plot the command is: "PGRP10;". Please note than not all devices support the RePlot
command.
A hardcoded printf()-based rectangle program is limited in usefulness. Therefore, let us write a simple
function that can draw an outline rectangle either to the screen or to an HP-GL/2 device.
void sd_rect(float xmin, float ymin, float xmax, float ymax, int color, int l_thick){
if(Output_Device==SCREEN){ /* send to screen */
SetAPen(rp, color);
Move(sd_rp, xmin,ymin);
Draw(sd_rp, xmax,ymin);
Draw(sd_rp, xmax,ymax);
Draw(sd_rp, xmin,ymax);
Draw(sd_rp, xmin,ymin);
}
else{
fprintf(Outfp,"SP%dPW%.3f", color,(float)(l_thick) *0.35);
fprintf(Outfp,"PU%f,%fPD%f,%f,%f,%f,%f,%f,%f,%f",
xmin,ymin,xmax,ymin,xmax,ymax,xmin,ymax,xmin,ymin);
}
return;
}
Many programming methods are possible for a function similar to sd_rect(), but this code was kept
simple for ease of understanding. The first fprinf() statement sets the pen color using the SP command.
Although HP-GL/2 can compensate for an attempt at selecting a pen number (i.e. color) greater than
supported by the plotter, it is best if the programmer keeps track of this. The PW command sets the Pen
Width. The default pen width is 0.35 mm. Therefore in our example we convert the screen oriented
l_thick variable to the Pen Width acceptable measure by multiplying 0.35 times l_thick. On many
HP-GL/2 devices, selecting a Pen Width greater than 0.35 mm results in the plotter making two or more
passes with the pen. If the pen in the plotter is 0.35 mm thick, it is not possible to reduce line thickness
below this.
The next fprintf() call is self explanatory and creates the outline of the rectangle. It is suggested to limit
the number of decimals sent to the plotter by modifying the fprintf() command. Use something line
PU%.3f,%.3fPD%.3f,%.3f..... to limit the decimal places.
Many times a rectangle must be filled with a specific color or pattern. HP-GL/2 supports a number of
approaches to this problem. The simplest program relies on the RA (fill Rectangle Absolute) command.
The command syntax is:
RAx,y
The first step to using the RA command is to use another command to position the pen at the upper left
corner of the desired rectangle. Therefore, a command string such as PU100,100RA200,200 creates a
square with the upper left corner at coordinates 100,100 and the lower right corner at 200, 200. The
defined rectangle is filled in with the currently defined pen color and fill type.
Fill Type is set by use of the FT command. The fills that FT can create are: solid, parallel lines,
crosshatched, or patterned (raster) fills. FT allows the programmer to define fill patterns for polygons,
rectangles, characters, and wedges (pie slices). The syntax for fill type is:
FT fill type(,option1, option2)
Setting fill type to 1 or 2 produces a solid color fill. The color of the fill is determined by the currently
selected pen (SP command). Options 1 and 2 are ignored for fill types 1 and 2. Setting fill type to 3
produces a fill composed of parallel lines. Option 1 determines the spacing between each line while
Option 2 determines the angle of the lines, where 0 degrees produces a horizontal line. Setting fill type
to 4 produces a crosshatched line. Options 1 and 2 are as discussed above. Setting fill type to 10
produces a shading effect. The percent of shading is determined by setting Option1 to the desired shade.
The percent of shading varies from 1-100%. One percent shading is almost no shading while 100%
shading is a solid color.
HP-GL/2 provides control over the pattern used to draw lines. The format of the Line Type (LT)
command is:
LTline type(,pattern length(,mode;))
To create a solid line, the LT command without parameters is sent to the plotter. Setting the line type
parameter to a number between 1 and 8 selects a pre-defined line pattern. HP-GL/2 supports eight
pre-defined line types. The pattern length parameter determines the distance it takes to complete one
pattern unit. If the mode parameter is set to "0", the value entered for the pattern length is a percentage
of the diagonal distance between P1 and P2. The default is 4%. If the mode parameter is set to "1", the
pattern length variable is interpreted in millimeters.
We now know how to move the pen, draw lines, change the colors of lines, set the line pattern, and the
line thickness. Creating functions that mimic the Amiga's Move() and Draw() functions is
straightforward.
/* global variables same as for Part 1 */
#define HPGL 2
void sd_Move(float x1, float y1){
if(Output_Device==SCREEN){
Move(sd_rp, (ULONG)(x1+0.5), (ULONG)(y1+0.5));
}
else if(Output_Device==HPGL){
fprintf(Outfp,"PU%.3f,%.3f", x1, y1);
}
return;
}
void sd_Draw(float x1, float y1, int color, int pat, int l_thick){
int i=0;
if(Output_Device==SCREEN){
/* See Part 1 */
}
else if(Output_Device==HPGL){
fprintf(Outfp,"SP%dPW%.3fLT%d,2,0PD%.3f,%.3f",color,
0.35*l_thick,pat,x1, y1);
}
return;
}
Although these two functions allow us to draw almost any wireframe shape, many drawings require
patterned fills of irregular shapes or complex filled patterns. HP-GL/2 supports a Polygon Mode (PM)
command. This command instructs the plotter to store all subsequent vector commands such as PU and
PD so that we can then fill the complex shape with any color or pattern we choose.
Sending the PM0 command to the plotter instructs the plotter to enter the polygon mode. Of note, the
initial vertex of our polygon will be the current pen position when we call PM0. Therefore, a PU or PA
command should move the pen to the first vertex of the polygon. After the PM0 command is entered,
the user sends a series of HP-GL/2 commands to define the polygon (e.g. PD, AA, CI, etc.). It is
recommended to close the polygon by ensuring that the last X, Y coordinate given when defining the
polygon is the same as the X, Y coordinate used to define the first vertex.
Once the polygon is defined, the user sends the PM2 command to the plotter. This terminates the
polygon and returns the plotter to a non-polygon mode. To fill a polygon, send the FP (Fill Polygon)
command to the plotter. To edge the polygon, send the EP (Edge Polygon) command to the plotter. It is
permissible to send both commands to the plotter such as FPEP so that the polygon is edged and filled.
The pen color of the fill or edge is set by the currently-defined color as set by the SP command. The fill
pattern used is set by calling the FT command prior to sending the FP command. In the same manner,
the line type used for the edging is determined by the currently defined line type which is set using the
LT command.
By programming a polygon function, we can create almost any shape we desire by just using this one
function. Therefore, we could use this function instead of the one we created above that drew a
rectangle. This polygon function can be used to create circles or ellipses. It is possible to create
complex polygons within polygons by use of the PM1 command, but I will just suggest the possibility
and refer the interested reader to the references stated at the end of this article. One point to keep in
mind is that not all devices that support HP-GL have a polygon buffer. For example, the HP7475A
plotter cannot take advantage of the PM commands.
Creating a polygon function requires that we pass X and Y arrays of vertices values. We must also
inform the function of the number of points, as well as the fill type, line type, color, and whether to fill,
edge, or both. A simple function is presented.
void sd_polygon(float *x, float *y, int pts, int f_color, int
l_color, int f_pat, int l_pat, int l_thick, BOOL fill, BOOL edge){
int i=0;
if(Output_Device==SCREEN){
/* see part 1 sd_AreaDraw2() */
}
else if(Output_Device==HPGL){
fprintf(Outfp,"PU%.3f,%.3fFT%dLT%dPM0PD", x[0], y[0], f_pat,l_pat);
for(i=1;i<(pts-1);i++) fprintf("%.3f,%.3f,",x[i],y[i]);
fprintf("%.3f,%.3fPM2", x[pts-1], y[pts-1]);
if(fill) fprintf("SP%dFP", f_color);
if(edge) fprintf("SP%dEP",l_color);
}
return;
}
The HP-GL/2 command set does not have anywhere near the level of control over text that PostScript
does, but HP-GL/2 does support simple plotting of text. Some of the newer plotters and many of the
raster-type devices (laser printers) that support HP-GL/2 commands even allow the user to select various
font families. The basic plotter usually has a default "stick" font built in that is used to plot text. Such a
basic plotter will not allow the selection of alternate font families, but will allow significant control over
the size, width, and slant of the font. Even for plotters that only support a stick font, the resourceful
programmer can send HP-GL/2 commands to the plotter to create any desired font type by defining the
font's shape.
The most important command for drawing text is the LB, or LaBel, command. This command is
followed by the desired text string and a specific string terminator that signifies the end of the text string.
When the LB command is sent to the plotter, the left edge of the text is placed at the current pen position
using the currently defined font, font size, and color. The default string terminator is the non-printing
end-of-text character ETX (decimal 3 in the ASCII character set). If this string terminator is not placed
at the end of the text, all HP-GL/2 commands following the first LB command are printed as part of the
text string.
An example LB command using a C function is:
fprintf(Outfp,"LB%s%c", "Example Text", 3);
It is a rather simple matter to create a function that mimics the AmigaDOS Text() function for output to
an HP-GL/2 device.
void sd_Text(char *str, int color){
if(Output_Device==SCREEN){
SetAPen(sd_rp, color);
Text(sd_rp, str, strlen(str));
}
else if(Output_Device==HPGL){
fprintf(Outfp,"SP%dLB%s%c", color, str, 3);
}
return;
}
Many plotters only support stick fonts. If your HP-GL/2 device supports a range of fonts, you may want
to use the SD, Standard Font Definition, command. This determines which character set, typeface, and
other parameters to use for the default font. The parameter list for this command is:
SDkind,value(,kind,value,kind,value,etc.)
where kind can be the integer values:
1 Character set, default value = 0 = Roman8
2 Font spacing, default value = 0 = fixed
3 Pitch, default value is media dependent
4 Height, default value is media dependent
5 Posture, default value is device dependent(normal,italic)
6 Stroke weight, default value = 0 = normal
7 Typeface, default value = 48 = stick fonts
A typical SD command might be:
SD2,1,4,14,5,0,6,3,7,5;
The 2,1 pair sets font spacing (2) to proportional (1). The 4,14 pair sets font height (4), to 14 points
(14). The 5,0 pair sets posture (5) to upright (0), the 6,3 pair sets stroke weight (6) to bold (3), and the
7,5 pair sets the typeface (7) to Times Roman (5).
Another text/font related command I find useful is the SI, Absolute Character Size, command. It sets the
height and width of a font to a specific size in centimeters. Because the plotter I use does not support
typefaces besides stick fonts, the SD command is of limited usefulness. The SI command on the other
hand allows me to size text so that the HP-GL/2 outputted text is the same relative size as what appears
on screen. I have found that bullet fonts as supported by AmigaDOS are generally about 20% narrower
than either PostScript or HP-GL/2 fonts. The SI command allows me to compensate for that discrepancy
as well as determine the character height. Because the SI command is an absolute measure in
centimeters, it is up to the programmer to scale the character size if the plot is scaled by altering the P1
and P2 positions.
The SI command parameter list is:
SIwidth,height;
A typical SI command in C might be:
fprintf(Outfp,"SI%.3f,%.3f",width, height);
A simple C function to scale the currently selected font for an HP-GL/2 graph is as follows.
void sd_FontSz(float fsize){ /* fsize is font size in points */
if(Output_Device==HPGL){
fprintf(Outfp,"SI%.3f,%.3f",fsize*0.5*2.54/72.*xscale,fsize*2.54/72.*yscale);
}
return;
}
The 2.54/72. calculation changes the font size in points to font size in centimeters. The xscale and
yscale variables will decrease or increase the font size the appropriate amount if the entire plot is scaled.
The 0.5 correction factor is arbitrary to have the font width of the HP-GL/2 text similar to the
AmigaDOS on-screen font width.
Although the HP-GL/2 command set is much larger than presented here, any hobbyist programmer can
create some impressive plotter graphics using the commands presented. As stated in the previous article,
I have included a simple C program entitled StructDraw.c that further demonstrates the HP-GL/2
language. The interested programmer can use this code as a basis for a more impressive program.
References:
HP-GL/2
The HP-GL/2 Reference Guide: A Handbook for Program Developers, Hewlett-Packard,
Addison-Wesley Publishing, 1990.
HP-GL
Interfacing and Programming Manual: HP 7475A Graphics Plotter, Hewlett Packard